package com.example.common.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @author addzero
 * @since 2022/10/1 9:15 AM
 */
public interface BigDecimals {
    /**
     * List一列求和
     *
     * @param collection 集合
     * @param getFun     得到乐趣
     * @return 返回信息
     * @author zjarlin
     * @since 2022/06/29
     */
    public static <E> BigDecimal sum(Collection<E> collection, Function<E, BigDecimal> getFun) {
        return collection.stream().filter(Objects::nonNull).filter(c -> Objects.nonNull(getFun.apply(c))).map(getFun)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * List一列乘积
     *
     * @param collection 集合
     * @param getFun     得到乐趣
     * @return 返回信息
     * @author zjarlin
     * @since 2022/06/29
     */
    static <E> BigDecimal multiply(Collection<E> collection, Function<E, BigDecimal> getFun) {
        return collection.stream().filter(Objects::nonNull).filter(c -> Objects.nonNull(getFun.apply(c))).map(getFun)
                .reduce(BigDecimal.ONE, BigDecimal::multiply);
    }

    @SafeVarargs
    static <E> BigDecimal sumproduct(Collection<E> collection, Predicate<E> condition, Function<E, BigDecimal>... getFun) {
        //默认四舍五入,保留两位
        return sumproduct(collection, condition, 2, RoundingMode.HALF_UP, getFun);
    }

    /**
     * sumproduct
     *
     * @param collection   集合
     * @param condition    条件
     * @param reservedBits 保留位
     * @param roundingMode 舍入模式
     * @param getFun       得到乐趣
     * @return {@link BigDecimal }
     * @author zjarlin
     * @since 2022/06/29
     */
    @SafeVarargs
    static <E> BigDecimal sumproduct(Collection<E> collection, Predicate<E> condition, int reservedBits, RoundingMode roundingMode, Function<E, BigDecimal>... getFun) {
        final BigDecimal reduce = collection.stream().filter(Objects::nonNull).filter(condition)
                .map(e -> {
                    final BigDecimal[] ret = {BigDecimal.ONE};
                    Arrays.stream(getFun).forEach(fn -> {
                        final BigDecimal bigDecimal = null == fn.apply(e) ? BigDecimal.ZERO : fn.apply(e);
                        ret[0] = ret[0].multiply(bigDecimal);
                    });
                    return ret[0];
                })
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return reduce.setScale(reservedBits, roundingMode);

    }
}
